package net.wangds.config.comp;

import net.wangds.common.base.funcs.Functions;
import net.wangds.config.module.Config;
import net.wangds.config.module.Dict;
import net.wangds.config.module.ParentConfig;
import net.wangds.config.module.ParentDict;
import net.wangds.config.repository.db.DictRepo;
import net.wangds.config.repository.db.SysConfigRepo;
import net.wangds.data.RemovedEnum;
import net.wangds.jdbc.comp.jdbc.JdbcComp;
import net.wangds.jpa.comp.AbstractRemovedComp;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import static net.wangds.jpa.Orders.CREATE_TM_ASC;

@Component
public class DictComp extends AbstractRemovedComp<Dict> {

    private DictRepo repo;

    @Autowired
    private JdbcComp mmJdbc;

    @Override
    @SuppressWarnings("unchecked")
    protected <T> Function<T, T> fetchCantFindNotById() {
        return (en) -> {
            if (en instanceof Config) {
                return (T) this.repo.findByCataAndItem(((Config) en).getCata(), ((Config) en).getItem()).orElse(null);
            } else {
                return null;
            }
        };
    }

    @Autowired
    public DictComp(DictRepo repo) {
        super(repo);
        this.repo = repo;
    }


    public Optional<Dict> findByCataAndItem(String cata, String key) {
        return repo.findByCataAndItemAndRemoved(cata, key, RemovedEnum.NORMAL);
    }


    public List<Dict> findByCata(String cata, Sort sort) {
        return repo.findByCataAndRemoved(cata, RemovedEnum.NORMAL, sort);
    }

    public Page<Dict> findByCata(String cata, String keywords, Pageable page) {

        if(StringUtils.isBlank(keywords)){
            return repo.findByCataAndRemoved(cata, RemovedEnum.NORMAL, page);
        }else {
            String sql = "SELECT t1.* FROM cnpgmt.sys_config t1\n" +
                    "where t1.removed = 0 and t1.cata = ? and (\n" +
                    "  t1.text regexp ? or t1.item regexp ? or t1.description regexp ?\n" +
                    ")";

            return mmJdbc.executeQuery(sql, new Object[]{cata, keywords, keywords, keywords},
                    page, Dict.class);
        }
    }

    public Page<Dict> findByCataLike(String cata, Pageable page) {
        return repo.findByCataLikeAndRemoved(cata, RemovedEnum.NORMAL, page);
    }

    @Cacheable(cacheNames = "always", key = "'dict-'+#cata+'-'+#item")
    public Dict cacheConfig(String cata, String item, String defaultValue) {
        return findByCataAndItem(cata, item).orElseGet(() -> {
            Dict c = new Dict();
            c.setCata(cata);
            c.setItem(item);
            c.setText(defaultValue);
            return save(c);
        });
    }

    @CachePut(cacheNames = "always", key = "'dict-'+#conf.cata+'-'+#conf.item")
    public Dict cacheConfig(Dict conf) {
        return save(conf);
    }

    @CacheEvict(cacheNames = "always", key = "'dict-'+#conf.cata+'-'+#conf.key")
    public void clearCache(Dict conf) {
    }

    public List<Dict> configTree(String cata) {
        List<Dict> allConfig = this.findByCata(cata, Sort.by(Sort.Order.asc("parentItem"), CREATE_TM_ASC));

        List<Dict> r = Functions.toTrees(allConfig.stream().map(ParentDict::of).peek(c -> {
            if (
                    CollectionUtils.isEmpty(c.getChildren())) {
                c.setChildren(null);
            }
        }).collect(Collectors.toList()), Dict::getItem, Dict::getParentItem, (p, c) -> {
            ParentDict res = Optional.of(p instanceof ParentDict ? (ParentDict) p : ParentDict.of(p)).get();
            if(res.getChildren()==null){
                res.setChildren(new ArrayList<>());
            }
            res.getChildren().add(c);
            return res;
        });

        return r;
    }


    @Override
    public Page<Dict> findByKeywords(String keywords, Pageable paging) {
        //TODO 按照关键字查询
        return this.findAll(paging);
    }
}

